package com.framework.admin.service.impl;

import com.framework.admin.repository.ModuleTableFieldRepository;
import com.framework.admin.domain.param.ModuleTableFieldParam;
import com.framework.admin.mapper.ModuleTableFieldMapper;
import com.framework.admin.model.ModuleForm;
import com.framework.admin.model.ModuleTableField;
import com.framework.admin.repository.ModuleFormRepository;
import com.framework.admin.service.IModuleTableFieldService;
import com.framework.common.config.SessionUtil;
import com.framework.common.exception.BusinessException;
import com.framework.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.util.List;


/**
 * @description: 模块数据表字段 Service
 * @author: lizurong
 * @version: 1.0
 * @date: 2021-03-24 11:18:24
 */
@Service
@Slf4j
@Transactional
public class ModuleTableFieldService implements IModuleTableFieldService {
    @Autowired
    private ModuleTableFieldMapper baseMapper;

    @Autowired
    private ModuleTableFieldRepository baseRepo;

    @Autowired
    private ModuleFormRepository moduleFormRepository;

    @Autowired
    EntityManager entityManager;

    @Override
    public Page<ModuleTableField> listPage(ModuleTableFieldParam param, PageRequest pageRequest) {
        String loginUserComCode = SessionUtil.getCompany().getCode() + "_";
        param.setTableName(loginUserComCode + param.getTableName());
        Page<ModuleTableField> page = baseMapper.listPage(param, pageRequest);
        for (ModuleTableField moduleTable : page.getContent()) {
            moduleTable.setTableName(moduleTable.getTableName().replace(loginUserComCode, ""));
        }
        return page;
    }

    @Override
    @Transactional
    public String save(ModuleTableField param) {
        String loginUserComCode = SessionUtil.getCompany().getCode() + "_";
        param.setTableName(loginUserComCode + param.getTableName());
        ModuleTableField dbEntity = baseRepo.getTopByColumnNameAndTableName(param.getColumnName(), param.getTableName());
        if (dbEntity != null) {
            throw new BusinessException("列名重复!");
        }
        ModuleTableField entity = baseRepo.save(param);
        //新增列
        this.doDDL("addColumn", entity);
        return entity.getId();
    }

    @Override
    public void genDbTable(String moduleFormId, String tableName, String tableDesc) {
        String loginUserComCode = SessionUtil.getCompany().getCode() + "_";
        ModuleForm moduleForm = moduleFormRepository.findOne(moduleFormId);
        if (moduleForm == null) {
            throw new BusinessException("模块id对应的数据不存在,可能已删除!");
        }
        moduleForm.setTableName(loginUserComCode + tableName);
        moduleForm.setTableDesc(tableDesc);
        //更新模块表
        moduleFormRepository.save(moduleForm);
        //生成自定义表
        this.genCustomTable(moduleForm.getTableName(), moduleForm.getTableDesc());
    }

    @Override
    public void deleteTable(String moduleFormId) {
        ModuleForm moduleForm = moduleFormRepository.findOne(moduleFormId);
        if (moduleForm == null) {
            throw new BusinessException("模块id对应的数据不存在,可能已删除!");
        }
        String oldTableName = moduleForm.getTableName();
        moduleForm.setTableName(null);
        moduleForm.setTableDesc(null);
        moduleFormRepository.save(moduleForm);//更新模块表
        //删除tableField 表字段
        baseRepo.deleteAllByTableName(oldTableName);
        this.deleteCustomTable(oldTableName);//删除自定义表
    }

    @Override
    public void editTableNameAndTableDesc(String moduleFormId, String tableName, String tableDesc) {
        ModuleForm moduleForm = moduleFormRepository.findOne(moduleFormId);
        if (moduleForm == null) {
            throw new BusinessException("模块id对应的数据不存在,可能已删除!");
        }
        String oldTableName = moduleForm.getTableName();
        String loginUserComCode = SessionUtil.getCompany().getCode() + "_";
        //更新模块表
        moduleForm.setTableName(loginUserComCode + tableName);
        moduleForm.setTableDesc(tableDesc);
        moduleFormRepository.save(moduleForm);
        //同步修改所有字段关联的表名
        baseRepo.updateByTableName(loginUserComCode + tableName, oldTableName);
        //修改表名和表描述
        this.updateCustomTableAndTableComment(oldTableName, loginUserComCode + tableName, tableDesc);
    }

    @Override
    public void delete(List<String> ids) {
        String[] arr = new String[ids.size()];
        for (String id : ids) {
            //删除列
            ModuleTableField entity = baseRepo.findOne(id);
            this.deleteColumn(entity.getTableName(), entity.getColumnName());
        }
        baseRepo.deleteById(ids.toArray(arr));

    }

    @Override
    public void update(ModuleTableField param) {
        ModuleTableField entity = baseRepo.findOne(param.getId());
        String loginUserComCode = SessionUtil.getCompany().getCode() + "_";
        param.setTableName(loginUserComCode + param.getTableName());
        if (!entity.getColumnName().equals(param.getColumnName())) {
            //修改了列名，则判断是否与其他列重复
            ModuleTableField dbEntity = baseRepo.getTopByColumnNameAndTableName(param.getColumnName(), param.getTableName());
            if (dbEntity != null) {
                throw new BusinessException("列名重复!");
            }
        }
        BeanUtils.copyProperties(param, entity, "id");
        this.updateColumn(entity);
        baseRepo.save(entity);
    }


    /**
     * 生成自定义表
     *
     * @param dbTableName 带公司code自定义表名
     * @return
     */
    private void genCustomTable(String dbTableName, String tableDesc) {
        ModuleTableField entity = new ModuleTableField();
        entity.setTableName(dbTableName);
        entity.setTableDesc(tableDesc);
        this.doDDL("genDbTable", entity);
    }

    private void deleteColumn(String dbTableName, String columnName) {
        ModuleTableField entity = new ModuleTableField();
        entity.setTableName(dbTableName);
        entity.setColumnName(columnName);
        this.doDDL("deleteColumn", entity);
    }

    private void updateColumn(ModuleTableField entity) {
        this.doDDL("updateColumn", entity);
    }

    public void deleteCustomTable(String tableName) {
        ModuleTableField entity = new ModuleTableField();
        entity.setTableName(tableName);
        this.doDDL("deleteTable", entity);
    }

    /**
     * 修改表名及表描述
     *
     * @param oldTableName
     * @param newTableName
     * @param comment
     */
    private void updateCustomTableAndTableComment(String oldTableName, String newTableName, String comment) {
        String renameTableNameSql = "alter table " + oldTableName + " rename to " + newTableName;
        String renameTableCommentSql = "alter table " + newTableName + " comment '" + comment + "'";
        this.doSql("editTableName", renameTableNameSql, newTableName);
        this.doSql("editTableDesc", renameTableCommentSql, newTableName);
    }

    @Override
    public int doDDL(String type, ModuleTableField entity) {
        String dbTableName = entity.getTableName();
        String sql = "";
        switch (type) {
            case "genDbTable":
                log.info("创建自定义表：{}", dbTableName);
                String existTable = baseMapper.getTableName(dbTableName);
                if (StringUtils.isNotEmpty(existTable)) {
                    throw new BusinessException(" 表名已存在，生成失败!");
                }
                sql = "create table `" + dbTableName + "`(\r\n`id` varchar(32) NOT NULL,\r\n`create_time` datetime DEFAULT NULL COMMENT '创建时间',\r\n`creater_id` varchar(32) DEFAULT NULL COMMENT '创建人ID',\r\n`creater_com_id` varchar(32) DEFAULT NULL COMMENT '更新人ID',\r\n`update_time` datetime DEFAULT NULL COMMENT '更新时间',\r\n`updater_id` varchar(32) DEFAULT NULL COMMENT '更新人ID',\r\n`version` int(11) DEFAULT '0' COMMENT '版本',\r\nPRIMARY KEY (`id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='" +
                        entity.getTableDesc() + "';";
                break;
            case "addColumn":
            case "updateColumn":
                String dataType = this.toDbType(entity.getDataType());
                String length = (entity.getDataType().equals("datetime") || entity.getDataType().equals("text")) ? "" : entity.getColumnLength().toString();
                String rightKh = (entity.getDataType().equals("datetime") || entity.getDataType().equals("text")) ? "" : ")";
                String fieldPoint = entity.getPoint() != 0 ? ("," + entity.getPoint().toString()) : "";
                String ifNull = entity.getIfNull().equals("null") ? " DEFAULT NULL" : " NOT NULL";
                if ("addColumn".equals(type)) {
                    log.info("添加自定义表的列：{}", dbTableName);
                    sql = "alter table " + entity.getTableName() + " add " + entity.getColumnName() + " " + dataType + length + fieldPoint + rightKh + ifNull + " comment '" + entity.getColumnDesc() + "';";
                } else {
                    log.info("修改自定义表的列：{}", dbTableName);
                    ModuleTableField oldEntity = baseMapper.getOne(entity.getId());
                    sql = "alter table " + entity.getTableName() + " change " + oldEntity.getColumnName() + " " + entity.getColumnName() + " " + dataType + length + fieldPoint + rightKh + ifNull + " comment '" + entity.getColumnDesc() + "';";
                }
                break;
            case "deleteColumn":
                log.info("删除自定义表的列：{}", dbTableName);
                sql = "alter table " + entity.getTableName() + " drop column " + entity.getColumnName();
                break;
            case "deleteTable":
                log.info("删除自定义表：{}", dbTableName);
                sql = "drop table if exists " + dbTableName;
                break;
            default:
                throw new BusinessException("未知类型");
        }
        return this.doSql(type, sql, dbTableName);
    }

    public int doSql(String type, String sql, String dbTableName) {
        int nativeQuery = 0;
        try {
            nativeQuery = entityManager.createNativeQuery(sql).executeUpdate();
        } catch (Exception e) {
            log.error(type + "失败：{}", dbTableName);
            log.error(type + "发生异常：{}", e.getMessage());
            throw new BusinessException(type + "失败!,请联系管理员!");
        }
        if (nativeQuery > 0) {
            log.info(type + "成功，表名称：{}", dbTableName);
        }
        return nativeQuery;
    }

    private String toDbType(String fieldType) {
        if (fieldType.equals("varchar")) {
            return "varchar(";
        } else if (fieldType.equals("text")) {
            return "text";
        } else if (fieldType.equals("int")) {
            return "int(";
        } else if (fieldType.equals("double")) {
            return "double(";
        } else if (fieldType.equals("datetime")) {
            return "datetime";
        }
        return null;
    }

}
